home *** CD-ROM | disk | FTP | other *** search
- /*
- * $RCSfile: checkPoint.c,v $
- * $Revision: 1.1.1.1 $
- * $Date: 1996/05/04 21:55:50 $
- */
- /**********************************************************************
- * EXODUS Database Toolkit Software
- * Copyright (c) 1991 Computer Sciences Department, University of
- * Wisconsin -- Madison
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY OF WISCONSIN --
- * MADISON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.
- * THE DEPARTMENT DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
- * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * The EXODUS Project Group requests users of this software to return
- * any improvements or extensions that they make to:
- *
- * EXODUS Project Group
- * c/o David J. DeWitt and Michael J. Carey
- * Computer Sciences Department
- * University of Wisconsin -- Madison
- * Madison, WI 53706
- *
- * or exodus@cs.wisc.edu
- *
- * In addition, the EXODUS Project Group requests that users grant the
- * Computer Sciences Department rights to redistribute these changes.
- **********************************************************************/
- #include "sysdefs.h"
- #include "ess.h"
- #include "checking.h"
- #include "trace.h"
- #include "error.h"
- #include "list.h"
- #include "pool.h"
- #include "tid.h"
- #include "io.h"
- #include "lock.h"
- #include "object.h"
- #include "msgdefs.h"
- #include "thread.h"
- #include "semaphore.h"
- #include "latch.h"
- #include "link.h"
- #include "lsn.h"
- #include "bf.h"
- #include "volume.h"
- #include "openlog.h"
- #include "trans.h"
- #include "logrecs.h"
- #include "logaction.h"
- #include "log.h"
- #include "threadstate.h"
- #include "util_funcs.h"
- #include "bf_extfuncs.h"
- #include "io_extfuncs.h"
- #include "log_intfuncs.h"
- #include "log_extfuncs.h"
- #include "thread_funcs.h"
- #include "thread_globals.h"
- #include "log_globals.h"
- #include "trans_globals.h"
-
-
- int
- checkPoint (
- BOOL syncForce
- )
- {
-
- register OPENLOG *openLog;
- CHECKPOINTMASTER *checkMaster;
- CHECKPOINTINFO checkInfo;
- CHECKPOINTDPTINFO dirtyPageInfoRecord;
- LOGRECORDINFO recordInfo;
- LOGRECORDHDR recordHeader;
- static CHECKTRANS transList[MAXTRANSCHKPNT];
- LSN lsn;
- LSNOFFSET tempLSN;
- int offset;
- int dirtyPages;
- FORCEMARK forceMark;
- int recordNum;
- int totalDPTLogged;
- int maxDPTPerRecord;
- int numToLog;
- BOOL checkpointStartRecorded;
- LSN tempOldestLSN;
- int i;
-
- TRPRINT(TR_LOG, TR_LEVEL_1, ("sync force:%d", syncForce));
-
-
- /*
- * get a pointer to the log
- */
- openLog = &OpenLog;
-
- /*
- * get the latch on the log
- */
- if (waitLatch( &(openLog->logLatch), SHARE_LATCH )) {
-
- SM_ERROR(TYPE_FATAL, Active->errno);
- }
-
- /*
- * check to see if the log is in use
- */
- if (waitSemaphore( &(openLog->writeSemaphore) )) {
-
- signalLatch( &(openLog->logLatch) );
- return(esmFAILURE);
- }
-
- /*
- * set the information in the master record
- */
- checkMaster = (CHECKPOINTMASTER *) openLog->controlBuffer->bufFrame;
-
- /* get the list of dirty pages */
- dirtyPages = (int)(checkInfo.numDirtyPages = checkPointDirtyPages());
-
- /*
- * check to see if a synchronous force is called for
- */
- if (syncForce) {
-
- /*
- * synchronously force dirty pages
- */
- forceDirtyPages(checkInfo.numDirtyPages);
-
- /*
- * there should be zero dirty pages
- */
- dirtyPages = (int) (checkInfo.numDirtyPages = 0);
- }
-
- /*
- * Make sure all pages written to unix file based volumes are
- * actually on disk.
- */
- if (io_SyncUnixFileVolumes() != esmNOERROR) {
- SM_ERROR(TYPE_FATAL, esmINTERNAL);
- }
-
- /*
- * get the list of active transactions and the log information
- */
- checkInfo.numActiveTrans = checkPointTrans(transList);
- checkInfo.wrapCount = openLog->wrapCount;
-
- /*
- * Get a list of all mounted volume id's
- */
- checkInfo.mountedVolCount = checkPointVolumes(CheckpointVolumes);
-
- /*
- * Log the dirty page table as a series of
- * LOG_ACTION_CKPNT_DIRTY_PAGES type log records.
- */
- totalDPTLogged = 0;
- recordNum = 0;
- maxDPTPerRecord = MAX_LOGIMAGE_LEN / 2; /* very conservative */
- checkpointStartRecorded = FALSE;
- while (totalDPTLogged < dirtyPages) {
-
- /*
- * initialize the fields of the record header
- */
- recordHeader.magic = LOGRECORD_MAGIC;
- recordHeader.type = LOG_REC_TYPE_CHECKPOINT;
- recordHeader.action = LOG_ACTION_CKPNT_DIRTY_PAGES;
- recordHeader.imageCount = 2;
- recordInfo.imageCount = 2;
- recordHeader.flags = NOFLAGS;
-
- numToLog = MIN(maxDPTPerRecord, dirtyPages - totalDPTLogged);
-
- /*
- * set the image for the checkpoint DPT info
- */
- dirtyPageInfoRecord.numDirtyPages = numToLog;
- dirtyPageInfoRecord.recordNum = recordNum;
- recordHeader.imageSize[0] = sizeof(dirtyPageInfoRecord);
- recordHeader.imageOffset[0] = 0;
- recordInfo.imageSize[0] = sizeof(dirtyPageInfoRecord);
- recordInfo.imageData[0] = (VOID *) &dirtyPageInfoRecord;
-
- /*
- * set the alignment for the next image
- */
- offset = ALIGN(sizeof(dirtyPageInfoRecord), 4);
- TRPRINT(TR_LOG, TR_LEVEL_2, ("offset:%d", offset));
-
- /*
- * setup the image for the dirty pages information
- */
- recordHeader.imageSize[1] = numToLog * sizeof(DIRTYPAGEINFO);
- recordHeader.imageOffset[1] = offset;
- recordInfo.imageSize[1] = recordHeader.imageSize[1];
- recordInfo.imageData[1] = (VOID *) (&(DirtyPageTable[totalDPTLogged]));
-
- /*
- * calculate the size of the record
- */
- recordHeader.length = sizeof(LOGRECORDHDR) + ALIGN(offset + recordHeader.imageSize[1], 4);
- TRPRINT(TR_LOG, TR_LEVEL_2, ("DPT record length:%d", recordHeader.length));
-
- /*
- * write the record to the log
- */
- lsn = writeLogRecordHeader(openLog, &recordHeader, &tempLSN);
-
- /*
- * write the images to the log
- */
- writeImage(openLog, &recordInfo, 0, &tempLSN);
- writeImage(openLog, &recordInfo, 1, &tempLSN);
-
- if ( !checkpointStartRecorded ) {
- /* record the checkpoint information in the openlog structure */
- openLog->checkPointUnique = openLog->logRecordCount;
- openLog->checkPointLSN = lsn;
- openLog->checkPointPid = LSN_TO_LOG_PAGE(lsn.offset, openLog);
- checkpointStartRecorded = TRUE;
- }
-
- /* Record the next LSN to be generated */
- openLog->nextValidLSN.wrapCount = openLog->wrapCount;
- openLog->nextValidLSN.offset =
- FIRST_LSN_ON_PAGE(openLog->tailLSN, openLog);
-
- totalDPTLogged += numToLog;
- recordNum++;
- }
- SM_ASSERT(LEVEL_3, totalDPTLogged == dirtyPages);
- SM_ASSERT(LEVEL_3, checkInfo.numDirtyPages < DirtyPageTableMaxSize);
-
-
- /*
- * NOW LOG THE CHECKPOINT RECORD
- */
-
- /*
- * Remember the mark to force to and increment the log's
- * count of log records. This is similar to the sequence of
- * events in writeLogRecord()
- */
- forceMark = ++(openLog->logRecordCount);
-
- /*
- * initialize the fields of the record header
- */
- recordHeader.magic = LOGRECORD_MAGIC;
- recordHeader.type = LOG_REC_TYPE_CHECKPOINT;
- recordHeader.action = LOG_ACTION_NO_ACTION;
- recordHeader.imageCount = 3;
- recordInfo.imageCount = 3;
- recordHeader.flags = NOFLAGS;
-
- /*
- * set the image for the checkpoint body
- */
- recordHeader.imageSize[0] = sizeof(CHECKPOINTINFO);
- recordHeader.imageOffset[0] = 0;
- recordInfo.imageSize[0] = sizeof(CHECKPOINTINFO);
- recordInfo.imageData[0] = (VOID *) &checkInfo;
-
- /*
- * set the alignment for the next image
- */
- offset = ALIGN(sizeof(CHECKPOINTINFO), 4);
- TRPRINT(TR_LOG, TR_LEVEL_2, ("offset:%d", offset));
-
- /*
- * setup the image for the active transaction information
- */
- recordHeader.imageSize[1] = checkInfo.numActiveTrans * sizeof(CHECKTRANS);
- recordHeader.imageOffset[1] = offset;
- recordInfo.imageSize[1] = recordHeader.imageSize[1];
- recordInfo.imageData[1] = (VOID *) transList;
-
- /*
- * set the alignment for the next image
- */
- offset = ALIGN(offset + recordHeader.imageSize[1], 4);
- TRPRINT(TR_LOG, TR_LEVEL_2, ("offset:%d", offset));
-
- /*
- * Set up the image for the mounted volumes info
- */
- recordHeader.imageSize[2] = checkInfo.mountedVolCount * sizeof(*CheckpointVolumes);
- recordHeader.imageOffset[2] = offset;
- recordInfo.imageSize[2] = recordHeader.imageSize[2];
- recordInfo.imageData[2] = (VOID *) CheckpointVolumes;
-
- /*
- * calculate the size of the record
- */
- recordHeader.length = sizeof(LOGRECORDHDR) + ALIGN(offset + recordHeader.imageSize[2], 4);
- TRPRINT(TR_LOG, TR_LEVEL_2, ("record length:%d", recordHeader.length));
-
- /*
- * write the record to the log
- */
- lsn = writeLogRecordHeader(openLog, &recordHeader, &tempLSN);
-
- /*
- * write the images to the log
- */
- writeImage(openLog, &recordInfo, 0, &tempLSN);
- writeImage(openLog, &recordInfo, 1, &tempLSN);
- writeImage(openLog, &recordInfo, 2, &tempLSN);
-
- if ( !checkpointStartRecorded ) {
- /* record the checkpoint information in the openlog structure */
- openLog->checkPointUnique = openLog->logRecordCount;
- openLog->checkPointLSN = lsn;
- openLog->checkPointPid = LSN_TO_LOG_PAGE(lsn.offset, openLog);
- checkpointStartRecorded = TRUE;
- }
-
- /* Record the next LSN to be generated */
- openLog->nextValidLSN.wrapCount = openLog->wrapCount;
- openLog->nextValidLSN.offset =
- FIRST_LSN_ON_PAGE(openLog->tailLSN, openLog);
-
- PRINT_PROGRESS( ("Logging CHECKPOINT at LSN:%d:%d\n", openLog->checkPointLSN.offset, openLog->checkPointLSN.wrapCount));
-
- /*
- * force the log
- */
- forceLog(forceMark);
-
- /*
- * set the information in the master record
- */
- checkMaster = (CHECKPOINTMASTER *) openLog->controlBuffer->bufFrame;
- checkMaster->magic = CHECKPOINTMASTER_MAGIC;
- checkMaster->wrapCount = openLog->wrapCount;
- checkMaster->checkRecordLSN = openLog->checkPointLSN;
- SM_ASSERT(LEVEL_3, checkInfo.numDirtyPages < DirtyPageTableMaxSize);
- checkMaster->oldestDirtyLSN = findOldestLSN(openLog, openLog->checkPointLSN,
- checkInfo.numDirtyPages);
-
- /*
- * dirty the page
- */
- DIRTY_PAGE(openLog->controlBuffer->pageHash);
-
- /*
- * force the master information to disk
- */
- bf_ForcePage(openLog->controlBuffer->pageHash, BF_SEM);
-
- /*
- * Find the LSN of the oldest dirty buffer page. If no page is
- * dirty, the the current checkpoint record LSN will be remembered.
- * This is used to determine where log space can be reused.
- */
- tempOldestLSN = openLog->checkPointLSN;
- for (i = 0; i < dirtyPages; i++) {
- if ( compareLSN(&DirtyPageTable[i].lsn, &tempOldestLSN) < 0) {
- tempOldestLSN = DirtyPageTable[i].lsn;
- }
- }
- OldestDirtyPageLSN = tempOldestLSN;
- PRINT_PROGRESS(("Checkpoint oldest dirty page lsn:%d:%d\n", OldestDirtyPageLSN.wrapCount, OldestDirtyPageLSN.offset));
-
- /*
- * check to see if a synchronous force is called for
- */
- if (syncForce) {
-
- /*
- * mark the checkpoint as done
- */
- openLog->flags ^= LOG_CHECKPOINT_IN_PROGRESS;
-
- /*
- * signal any waiters
- */
- notify( &(openLog->checkPointList), esmNOERROR, esmNOERROR);
-
- /* since all pages were flushed, remember this checkpoint */
- LastFlushedCheckpoint = checkMaster->checkRecordLSN;
-
- } else {
-
- /*
- * start the thread which asynchronously forces the dirty
- * page table.
- */
- notify(&DirtyPageFlushWaitList, esmNOERROR, esmNOERROR);
-
- /*
- * signal any waiters for the checkpoint
- */
- notify( &(openLog->checkPointList), esmNOERROR, esmNOERROR);
- }
-
- /*
- * reset the number of records since checkpoint
- */
- openLog->checkPointCount = 0;
-
- /*
- * give the semaphore back
- */
- signalSemaphore( &(openLog->writeSemaphore) );
-
- /*
- * give the log latch back
- */
- signalLatch( &(openLog->logLatch) );
-
- return(esmNOERROR);
- }
-